package Schiffeversenken;

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import java.util.Random;
import java.util.Vector;
import javax.microedition.media.*;

public class GameInstance extends MIDlet implements CommandListener
{
    // static consts
    static final int    COLS        = 8;
    static final int    ROWS        = 8;
    static final int    FIELDWIDTH  = 15;
    static final int    SHIPAMOUNT  = 5;

    static final int    CONNECTION_TIMEOUT  = 15;
    static final int    AWAIT_ENEMY_SHOOT   = 30;

    
    // members
    private Command     _exitCommand;           // the exit command
    private Command     _clientServerCommand;   // choose whether this is client or server command
    private Command     _playCommand;           // the play command
    private Command     _backCommand;           // back to upper menu command
    private Display     _display;               // the display for this MIDlet
    private ChoiceGroup _clientServerChoice;    // choice if this is a server or a client

    private String[]    _imageList;
    private String[]    _textList;

    private Form        _mainForm;
    private Image       _menuBackgroundImage;
    private ImageItem   _menuBackgroundImageItem;

    /*
     * 0    -   root menu
     * 1    -   gameplay
     * 2    -   client/server selection
     * 3    -   client/server waiting screen
     * */
    private int         _currentState;

    private BMESound _AudioIntro;

    private BTClient client;
    private BTServer server;

    /** if true BTconnection is established */
    private boolean ConnectionEstablished = true;

    // constructors
    public GameInstance()
    {
        _display                = Display.getDisplay(this);
        _exitCommand            = new Command("Exit", Command.EXIT, 1);
        _clientServerCommand    = new Command("New Game", Command.SCREEN, 0);
        _playCommand            = new Command("OK", Command.SCREEN, 0);
        _backCommand            = new Command("Back", Command.BACK, 1);
        _currentState           = 0;

        _imageList      = new String[3];
        _imageList[0]   = "/MainMenu_eng.png";
        _imageList[1]   = "/MainMenu_eng_120.png";
        _imageList[2]   = "/MainMenu_eng_240.png";

        _mainForm       = new Form ("Schiffe versenken");

        _mainForm.addCommand(_exitCommand);
        _mainForm.addCommand(_clientServerCommand);
        _mainForm.setCommandListener(this);

        _AudioIntro = new  BMESound(new String("/intro.wav"), new String("audio/x-wav"), -1);


        try
        {
            _menuBackgroundImage = Image.createImage( _imageList[2] );
        } catch (Exception ex) {}

        _menuBackgroundImageItem = new ImageItem("", _menuBackgroundImage, ImageItem.LAYOUT_VCENTER,"menu_bg");

        _clientServerChoice = new ChoiceGroup("Choose between Server and Client", ChoiceGroup.EXCLUSIVE, new String[] {"Client", "Server"}, new Image[] {null, null});
        _clientServerChoice.setLayout(ChoiceGroup.LAYOUT_VCENTER | ChoiceGroup.LAYOUT_CENTER);

        try
        {sunkenImage = Image.createImage( "/message_sunken.png" );
        } catch (Exception ex) {}
    }

    // public methods
    public void startApp()
    {
        setGameState(_currentState);
        _display.setCurrent(_mainForm);

        // Sound für Intro
        _AudioIntro.start();
    }

    public void pauseApp() {}

    public void destroyApp(boolean unconditional)
    {
       
    }

    public void commandAction(Command c, Displayable s)
    {
        if (c == _exitCommand)
        {
            System.out.println("STATE: " + _currentState);
            switch(_currentState)
            {
                case 0:
                    destroyApp(false);
                    notifyDestroyed();
                    break;
                case 1:
                    setGameState(0);
                    break;
                default:
                    setGameState(0);
                    break;
            }
        }
        else if (c == _playCommand)
        {
            initBlueTooth(_clientServerChoice.getSelectedIndex() == 1);
            // start the game
            //setGameState(1);
        }
        else if (c == _backCommand)
        {
            // back to root menu
            setGameState(0);
        }
        else if (c == _clientServerCommand)
        {
            // go to client/server selection
            setGameState(2);
            _AudioIntro.stop();
        }
    }

    /** (Re-)Initializes BlueTooth connection.
     * @param <boolean> isServer If true this is a server, else this is a client.
     */
    private void initBlueTooth(boolean isServer)
    {
        System.out.println("initializing BT as server:" + String.valueOf(isServer));
        if (isServer)
        {
            this.server = new BTServer(this);
        }
        else
        {
            this.client = new BTClient(this);
        }
        // switch to connection waiting screen
        this.setGameState(3);
        
        /*
        // debug test!
        System.out.println("initializing BT ...");
        if (_btConnection == null)
        {
            _btConnection = new BTThread();
        }

        // @todo: replace with parsed parameter
        _btConnection.isServer = true;
        _btConnection.StartThread();
        // @todo: switch to loading screen and wait for BT thread to succeed/fail/timeout
        System.out.println("done Initializing BT!");

        while (_btConnection.GetServerState() != 2)
        {
            try
            {
                Thread.sleep(100);
            } 
            catch (InterruptedException ex)
            {
                ex.printStackTrace();
            }
        }
        // test server intialized - init test client

        System.out.println("Initializing BT test!");
        BTThread btTest = new BTThread();
        btTest.isServer = false;
        btTest.StartThread();
        System.out.println("done Initializing BT Test!");
         * */
    }

    public void BTReady()
    {
        this.setGameState(1);
    }

    public void OpponentQuit()
    {
        // @todo: inform player opponent has quit and quit game
    }

    // private methods
    public void setGameState(int state)
    {
        System.out.println("switching state from " + String.valueOf(_currentState) + " to " + String.valueOf(state));
        _currentState = state;
        switch( state )
        {
            // start game
            case 1:
                // @todo: remove "waiting for opponent placement screen"
                _mainForm.deleteAll();

                _mainForm.addCommand(_exitCommand);
                Battleground newBattleground = new Battleground("", Display.getDisplay(this));
                if (this.client != null)
                {
                    this.client.battleground = newBattleground;
                    newBattleground.btClient = this.client;
                }
                else
                {
                    this.server.battleground = newBattleground;
                    newBattleground.btServer = this.server;
                }
                _mainForm.append (newBattleground);
                break;
            // let player choose between client and server
            case 2:
                _mainForm.deleteAll();
                _mainForm.removeCommand(_clientServerCommand);
                _mainForm.removeCommand(_exitCommand);

                _mainForm.addCommand(_playCommand);
                _mainForm.addCommand(_backCommand);
                _mainForm.append(_clientServerChoice);
                break;
            // BTconnection waiting screen
            case 3:
                _mainForm.deleteAll();
                _mainForm.removeCommand(_clientServerCommand);
                _mainForm.removeCommand(_exitCommand);

                _mainForm.addCommand(_backCommand);
                String searchString = "Searching for ";
                if (this.client != null)
                {
                    searchString += "Servers ...";
                }
                else
                {
                    searchString += "Clients ...";
                }
                _mainForm.append(new Gauge(searchString, false, Gauge.INDEFINITE, Gauge.CONTINUOUS_RUNNING));
                break;
            // start screen
            default:
                _mainForm.deleteAll();
                _mainForm.removeCommand(_playCommand);
                _mainForm.removeCommand(_backCommand);
                if (this.client != null)
                {
                    this.client.cancelSearch();
                    this.client.destroy();
                }
                else if (this.server != null)
                {
                    // @todo: stop server thread if still in acceptAndOpen-Mode
                    this.server.destroy();
                }

                _mainForm.addCommand(_clientServerCommand);
                _mainForm.addCommand(_exitCommand);
                _mainForm.append(_menuBackgroundImageItem);
                break;
        }
    }

    // static methods
    public static Image resizeImage(Image src, int width, int height)
    {
        int srcWidth    = src.getWidth();
        int srcHeight   = src.getHeight();

        Image tmp       = Image.createImage(width, srcHeight);
        Graphics g      = tmp.getGraphics();
        int ratio       = (srcWidth << 16) / width;
        int pos         = ratio / 2;

        // horizontal resize
        for ( int x = 0; x < width; x++ )
        {
            g.setClip(x, 0, 1, srcHeight);
            g.drawImage(src, x - (pos >> 16), 0, Graphics.LEFT | Graphics.TOP);
            pos += ratio;
        }

        Image resizedImage  = Image.createImage(width, height);
        g                   = resizedImage.getGraphics();
        ratio               = (srcHeight << 16) / height;
        pos                 = ratio / 2;

        // vertical resize
        for ( int y = 0; y < height; y++ )
        {
            g.setClip(0, y, width, 1);
            g.drawImage(tmp, 0, y - (pos >> 16), Graphics.LEFT | Graphics.TOP);
            pos += ratio;
        }

        return resizedImage;
    }

    public static Image resizeTransparentImage(Image src, int width, int height)
    {
       // return resizeImage(src, width, height);
        
        int rgb[] = new int[src.getWidth()*src.getHeight()];
        src.getRGB(rgb,0,src.getWidth(),0,0,src.getWidth(),src.getHeight());
        int rgb2[] = reescalaArray(rgb,src.getWidth(),src.getHeight(),width,height);
        return Image.createRGBImage(rgb2,width,height,true);
    }

    public static int[] reescalaArray(int[] ini, int x, int y, int x2, int y2)
    {
        int out[] = new int[x2*y2];
        for (int yy = 0; yy < y2; yy++)
        {
            int dy = yy * y / y2;
            for (int xx = 0; xx < x2; xx++)
            {
                int dx = xx * x / x2;
                out[(x2*yy)+xx]=ini[(x*dy)+dx];
            }
        }
        return out;
    }

    public static String[] str_split (String original, String separator)
    {
        Vector nodes = new Vector();

        // Parse nodes into vector
        int index = original.indexOf(separator);
        while(index>=0)
        {
            nodes.addElement( original.substring(0, index) );
            original = original.substring(index+separator.length());
            index = original.indexOf(separator);
        }

        // Get the last node
        nodes.addElement( original );

        // Create splitted string array
        String[] result = new String[ nodes.size() ];
        if( nodes.size()>0 )
        {
            for(int loop=0; loop<nodes.size(); loop++)
            {
                result[loop] = (String)nodes.elementAt(loop);
            }
        }

        return result;
    }

    public static long getRandomSeed()
    {
        Random rand = new Random();
        return rand.nextLong();
    }


    public static int getMaxValue(int[] numbers)
    {
        int maxValue = numbers[0];
        for(int i=1;i < numbers.length;i++)
        {
            if(numbers[i] > maxValue)
            {
                maxValue = numbers[i];
            }
        }
        return maxValue;
    }
    public static int getMinValue(int[] numbers)
    {
        int minValue = numbers[0];
        for(int i=1;i<numbers.length;i++)
        {
            if(numbers[i] < minValue)
            {
                minValue = numbers[i];
            }
        }
        return minValue;
    }
    public static Image sunkenImage;
    public static Image getSunkenMessage()
    {
        return sunkenImage;
    }
    // buffer for read messages
    public Vector receivedMessages = new Vector(10);

    /** Call this after ENEMY player has done ship placement and game can
     * start
     */
    public void OpponentReady(boolean ourTurn)
    {
        System.out.println("game start");
        if (ourTurn)
        {

        }
        else
        {
            
        }
    }

    /**
     * Informs the error during the images search.
     */
    void informSearchError (String resMsg) {
        Alert al = new Alert("Error", resMsg, null, AlertType.ERROR);
        al.setTimeout(1000);
        this._display.setCurrent(al, this._mainForm);
    }

    /**
     * Informs the error during the selected image load.
     */
    void informLoadError (String resMsg) {
        Alert al = new Alert("Error", resMsg, null, AlertType.ERROR);
        al.setTimeout(1000);
        this._display.setCurrent(al, this._mainForm);
    }
}
